# project.py

# dome is 1.80 x 1.39 at the bottom and 1.39 high.

from __future__ import division

import math

from ot_simulator import project
from ot_simulator.cutting_pass import cutting_pass, rapid_funs
from ot_simulator.setup import setup
from ot_simulator.component import *
from ot_simulator.transform import transform

from ot_simulator.cutting_pass.debuggers import graph, minmax

from ot_simulator.template.param_funs import (
    param_ref, param_fun, param_eval, fun_value, get_param,
  )

from ot_simulator.template.template_funs import (repeating_template,
                                                 file_multi_num, frange)

from ot_simulator.output.outputer import file
from ot_simulator.output.anilam import series_1100

#Semi_major = 1.80
#Semi_minor = 1.39
# half_circumference 4.94860882436

# 1.325 aspect ratio
Semi_major = 1.7225
Semi_minor = 1.3
# half_circumference 4.67795468496

Height = Semi_minor

#Tool_radius = 0.7555 / 2       # HSS router bit
#Tool_radius = 0.6275 / 2       # New carbide router bit
Tool_radius = 0.375 / 2         # ball end mill

# min 13
# if this is even, then the 90 deg line will match the 0 deg line.
Num_steps = 14                  # .334" per step, 89% of tool diameter
                                # flute height on flat surface 0.102"
Step_inc = 180.0/Num_steps

Comments = (
    'X is the major axis, Y the minor axis, and Z the height.',
    'Align X to 2.0 inches from end of wood.',
    'Align Y centered on width of wood.',
    'Align Z to the top of wood.',
  )

def offset_fn(point, params):
    return transform.translation(z=-get_param(params, 'cutting_depth')) \
                    .inverse() \
                    .add(point) \
                    .move(z=Tool_radius + get_param(params,
                                                    'roughing_offset'))

def e_polar(angle):
    r'''Returns the distance from the origin of the ellipse at ``angle``.

    From http://en.wikipedia.org/wiki/Ellipse#Polar_form_relative_to_center
    '''
    ang_radians = math.radians(angle)
    c, s = math.cos(ang_radians), math.sin(ang_radians)
    a, b = Semi_major, Semi_minor
    return a * b / math.hypot(b * c, a * s)

def division_template():
    r'''Divides the ellipse into 360 equally distant divisions.

    Given X, the number of 360 divisions desired, returns the angle of the
    ellipse, such that the arc on the ellipse from 0 to that angle gives X/360
    part of the circumference of the ellipse.
    '''
    circumference = 0.0
    points = []
    inc_deg = 1
    inc_radians = math.radians(inc_deg)
    for angle in frange(inc_deg, 0, 360):
        points.append((circumference, angle))
        circumference += inc_radians * e_polar(angle)
    total_circumference = points[-1][0]
    print "total_circumference", total_circumference
    return repeating_template((360.0 * c / total_circumference, angle)
                              for c, angle in points)

#Graph1 = graph(x=param_ref('capture.x'), y=param_ref('capture.y'))
#Graph2 = graph(x=param_ref('capture.x'),
#               y=param_fun(lambda angle: (angle - 90.0)/35.0,
#                           'headstock.index'))
#Capture_x = minmax("capture.x", param_ref('capture.x'))
#Capture_y = minmax("capture.y", param_ref('capture.y'))
#Capture_z = minmax("capture.z", param_ref('capture.z'))
#
#    graph(x=param_ref('capture.x'),
#          y=param_fun(lambda angle: (angle - 90.0)/35.0,
#                      'headstock.index')),
#    minmax("zero_capture.x", param_ref('zero_capture.x')),
#    minmax("zero_capture.y", param_ref('zero_capture.y')),
#    minmax("zero_capture.z", param_ref('zero_capture.z')),
#    minmax("sr_capture.x", param_ref('sr_capture.x')),
#    minmax("sr_capture.y", param_ref('sr_capture.y')),
#    minmax("sr_capture.z", param_ref('sr_capture.z')),
#    minmax("tool_capture.x", param_ref('tool_capture.x')),
#    minmax("tool_capture.y", param_ref('tool_capture.y')),
#    minmax("tool_capture.z", param_ref('tool_capture.z')),
#    minmax("slide_rest._combined_sr", param_ref('slide_rest._combined_sr')),

dome_setup = \
  setup('dome_setup',
        (
            headstock(),
            elliptical_chuck(
              e     = param_eval(
                        '$e_polar($dome_chuck.nosewheel_index) - $Height'),
              sr    = param_ref('Height')),
            dome_chuck(
              nosewheel_index = param_fun(division_template(), 'step_index')),
        ),
        (
            slide_rest(
              tool_offset = param_ref('Height')),
            swivel(
              axis  = 'X',
              angle = param_ref('elliptical_chuck.tangent')),
        ),
        (cutting_pass.update_params(
             speed=5000, feed=30,

             # No funny business here: X->X, Y->Y, Z->Z
             clear1="Z2.0", clear2="Z2.0",
             out="Z2.0",

             tool=3, tool_desc='3/8" ball end mill',

             cutting_depth_inc=0.3475,   # 4 roughing passes
             roughing_offset = 0.03,
             lineno = 1000,

             Semi_major = Semi_major,
             Semi_minor = Semi_minor,
             Height     = Height,
             Step_inc   = Step_inc,
             e_polar    = fun_value(e_polar),
           ),
         cutting_pass.add_debuggers(
           ),
         cutting_pass.add_offset_fn(offset_fn),
         cutting_pass.sequence(
           cutting_pass.step('cutting_depth',
                             param_eval('-$cutting_depth_inc'),
                             param_ref('Height'),
                             0.0),
           cutting_pass.update_params(
               cutting_depth     = 0.0,
               cutting_depth_inc = 0.0,
               roughing_offset   = 0.0,
               lineno            = 2000,
             ),
         ),
         cutting_pass.cut(),
         cutting_pass.step('step_index',
                           param_ref('Step_inc'),
                           0.0,
                           param_eval('360.0 - $Step_inc')),
         cutting_pass.gen_pass(
           rapid_funs.rapid2_work_coord(
             'Z', param_eval('$cutting_depth_inc + 0.20'))),
         cutting_pass.step('index', param_ref('index_inc'), 0.0, 90.0),
         cutting_pass.generate(),
        ),
        full  = dict(index_inc = 0.5),
        quick = dict(index_inc = 30.0),
    )

dome_piece = project.piece('Elliptical Dome', dome_setup)

dome_piece.add_comments(*Comments)

dome_project = project.project('dome', dome_piece)

def dump(msg, x):
    print msg, x
    return x

def test_pickle(filename='dome.pkl'):
    import cPickle as pickle
    with open(filename, 'wb') as f:
        pickle.dump(dome_project, f, pickle.HIGHEST_PROTOCOL)

Height_waste_amount = 0.125
Z_offset = -(Height + Height_waste_amount + Tool_radius)

def full(filename='dome_full.m'):
    dest_machine = series_1100(file(), z_offset=Z_offset)
    dome_piece.run('full', dest_machine, filename)

def quick(filename='dome_quick.m'):
    dest_machine = series_1100(file(), z_offset=Z_offset)
    dome_piece.run('quick', dest_machine, filename)

